package com.koron.common.core.business.workflow.templates;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.koron.bean.query.Page;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.bean.workflow.DefineParam;
import com.koron.common.core.business.todoApproval.templates.TodoApprovalHandler;
import com.koron.common.core.business.todoApproval.util.StringEvent;
import com.koron.common.core.business.workflow.bean.param.BaseParam;
import com.koron.common.core.business.workflow.bean.param.ListParam;
import com.koron.common.core.business.workflow.bean.param.StartParam;
import com.koron.common.core.business.workflow.bean.param.SubmitParam;
import com.koron.common.core.business.workflow.bean.po.SysWorkflow;
import com.koron.common.core.business.workflow.bean.properties.WorkflowProperties;
import com.koron.common.core.business.workflow.bean.result.DefineResult;
import com.koron.common.core.business.workflow.bean.result.FlowList;
import com.koron.common.core.business.workflow.bean.result.TaskStatistics;
import com.koron.common.core.business.workflow.bean.result.UserResult;
import com.koron.common.core.business.workflow.service.SysWorkflowService;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author jzp
 * @since 2021/3/16 11:24
 */
@Slf4j
@Component
public class WorkFlowHandler {
    @Autowired
    private SysWorkflowService sysWorkflowService;

    @Autowired
    private TodoApprovalHandler todoApprovalHandler;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    private String getAccount() {
        return ThreadLocalContext.get().getAccount();
    }

    /**
     * 启动工作流
     *
     * @param workflowProperties 工作流属性
     * @param dataId             业务数据id
     * @param dataCode           业务数据编号
     * @param formVariables      表单数据,可以为null
     * @return billId
     */
    @Deprecated
    public SysWorkflow start(WorkflowProperties workflowProperties, String dataId, String dataCode, String dataTitle, Map<String, String> formVariables) {
        String operator = getAccount();
        BaseParam baseParam = workflowProperties.baseParam();
        String billId;
        if (formVariables == null) {
            formVariables = new HashMap<>();
        }
        SysWorkflow sysWorkflow = sysWorkflowService.queryRunByDataId(dataId);
        // 存在工作流则直接进入提交
        if (sysWorkflow != null) {
            billId = sysWorkflow.getBillId();
            sysWorkflow = WorkFlowTemplates.executeSubmit(baseParam, billId, operator, sysWorkflow.getOneTaskId(), "同意", formVariables);
            sysWorkflow.setBillId(billId);
            sysWorkflow = sysWorkflowService.update(sysWorkflow);
            try {
                // @TODO 2023-08-23 用于后续待办根据流程创建时间判断，参考GdhWaterTodoApprovalModel.getCompatibilityAppName
                EamUser eamUser = ThreadLocalContext.get();
                eamUser.setCreateTime(sysWorkflow.getCreateTime());

                todoApprovalHandler.createTodo(dataId, dataTitle, sysWorkflow.getCurNodeUserId(), operator, workflowProperties.getProcessCode(), new Date(), sysWorkflow.getModuleCode());
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        } else {
            billId = CodeTools.getCode32();
            // 启动工作流，进入审批流程
            sysWorkflow = WorkFlowTemplates.executeStart(baseParam, billId, operator, formVariables, dataCode, dataTitle);
            sysWorkflow.setBillId(billId);
            sysWorkflow.setDataCode(dataCode);
            sysWorkflow.setDataId(dataId);
            sysWorkflow.setDataTitle(dataTitle);
            BeanUtils.copyProperties(baseParam, sysWorkflow);
            sysWorkflow.setModuleCode(workflowProperties.getModuleCode());
            // 存储到工作流表
            sysWorkflow = sysWorkflowService.insert(sysWorkflow);
            try {
                // @TODO 2023-08-23 用于后续待办根据流程创建时间判断，参考GdhWaterTodoApprovalModel.getCompatibilityAppName
                EamUser eamUser = ThreadLocalContext.get();
                eamUser.setCreateTime(sysWorkflow.getCreateTime());

                todoApprovalHandler.startTodo(dataId, dataTitle, sysWorkflow.getCurNodeUserId(), operator, workflowProperties.getProcessCode(), new Date(), sysWorkflow.getModuleCode());
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
        sysWorkflow.setDataCode(dataCode);
        return sysWorkflow;
    }

    /**
     * 工作流启动
     */
    public SysWorkflow start(StartParam startParam, String dataId, String dataCode, String dataTitle, WorkflowProperties workflowProperties) {
        startParam.setBillId(CodeTools.getCode32());
        startParam.setTitle(dataTitle);
        SysWorkflow sysWorkflow = WorkFlowTemplates.executeStart(startParam);
        BeanUtils.copyProperties(workflowProperties.baseParam(), sysWorkflow);
        sysWorkflow.setBillId(startParam.getBillId());
        sysWorkflow.setDataCode(dataCode);
        sysWorkflow.setDataId(dataId);
        sysWorkflow.setDataTitle(dataTitle);
        sysWorkflow.setModuleCode(workflowProperties.getModuleCode());

        // 存储到工作流表
        sysWorkflow = sysWorkflowService.insert(sysWorkflow);
        try {
            // @TODO 2023-08-23 用于后续待办根据流程创建时间判断，参考GdhWaterTodoApprovalModel.getCompatibilityAppName
            EamUser eamUser = ThreadLocalContext.get();
            eamUser.setCreateTime(sysWorkflow.getCreateTime());

            todoApprovalHandler.startTodo(dataId, dataTitle, sysWorkflow.getCurNodeUserId(), startParam.getOperator(), workflowProperties.getProcessCode(), new Date(), sysWorkflow.getModuleCode());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return sysWorkflow;
    }

    /**
     * 工作流提交
     */
    public SysWorkflow submit(SubmitParam submitParam, SysWorkflow sysWorkflowBefore, String dataCode, String dataTitle) {
        SysWorkflow sysWorkflow = WorkFlowTemplates.executeSubmit(submitParam);
        sysWorkflow.setBillId(submitParam.getBillId());
        String curNodeCode = sysWorkflow.getCurNodeCode();
        // 实时更新dataCode数据
        if (!StringUtils.isEmpty(dataCode)) {
            sysWorkflow.setDataCode(dataCode);
        }
        if (!StringUtils.isEmpty(dataTitle)) {
            sysWorkflow.setDataTitle(dataTitle);
        }

        // 更新
        sysWorkflow = sysWorkflowService.update(sysWorkflow);

        // BeanUtils.copyProperties(sysWorkflow, sysWorkflowBefore);
        // END节点CANCEL节点更新业务状态
        if (StrUtil.contains(curNodeCode, "CANCEL")) {
            // 如果作废，结束表中的对应数据
            sysWorkflowService.finishById(sysWorkflow.getBillId());
        } else if (Arrays.stream(curNodeCode.split(";")).allMatch("END"::equals)) {
            // 如果结束，所有节点都结束了才结束
            sysWorkflowService.finishById(sysWorkflow.getBillId());
            applicationEventPublisher.publishEvent(new StringEvent(this,sysWorkflow.getBillId()));
        }
        // 创建待办并设置已办
        if (sysWorkflow.getCurNodeUserName() == null) {
            todoApprovalHandler.submit(sysWorkflowBefore.getDataId(), sysWorkflow.getTitle(), sysWorkflowBefore, !Objects.equals(sysWorkflowBefore.getCurNodeCode(), sysWorkflow.getCurNodeCode()), null, submitParam, new Date(), sysWorkflow.getModuleCode());
        } else {
            todoApprovalHandler.submit(sysWorkflowBefore.getDataId(), sysWorkflow.getTitle(), sysWorkflowBefore, !Objects.equals(sysWorkflowBefore.getCurNodeCode(), sysWorkflow.getCurNodeCode()), sysWorkflow.getCurNodeUserId(), submitParam, new Date(), sysWorkflow.getModuleCode());
        }
        return sysWorkflow;
    }

    /**
     * 结束流程
     *
     * @param dataId 业务数据id
     * @return true成功，false失败
     */
    public boolean end(String dataId) {
        SysWorkflow sysWorkflow = sysWorkflowService.queryRunByDataId(dataId);
        if (sysWorkflow == null) {
            // 流程已结束或不存在
            return false;
        }
        BaseParam baseParam = sysWorkflow.drawBaseParam();
        String processInstanceId = sysWorkflow.getProcessInstanceId();
        String operator = getAccount();
        String s = WorkFlowTemplates.end(baseParam, processInstanceId, operator);
        JSONObject jsonObject = JSON.parseObject(s);
        todoApprovalHandler.allDone(dataId, operator, sysWorkflow.getModuleCode());
        return jsonObject.getInteger("code") != -1;
    }

    /**
     * 删除流程
     *
     * @param dataId 业务数据id
     * @return true成功，false失败
     */
    public boolean delete(String dataId) {
        if (StringUtils.isEmpty(dataId)) {
            return false;
        }
        // 一条业务数据对应多条流程
        List<SysWorkflow> sysWorkflows = sysWorkflowService.queryByDataId(dataId);
        // 删除流程和业务流程
        if (!CollectionUtils.isEmpty(sysWorkflows)) {
            for (SysWorkflow sysWorkflow : sysWorkflows) {
                BaseParam baseParam = sysWorkflow.drawBaseParam();
                String processInstanceId = sysWorkflow.getProcessInstanceId();
                String s = WorkFlowTemplates.delete(baseParam, processInstanceId);
                todoApprovalHandler.deleteTodo(dataId, sysWorkflow.getModuleCode());
                JSONObject jsonObject = JSON.parseObject(s);
                if (jsonObject.getInteger("code") == -1) {
                    log.error("工作流删除异常");
                    log.error("msg" + jsonObject.toString());
                    return false;
                }
            }
        }
        sysWorkflowService.deleteByDataId(dataId);
        return true;
    }

    /**
     * 获取用户在工作流中的数据
     *
     * @param listParam::type      类型
     *                  * 1我发起的
     *                  * 2我待审的（未办理、可认领、可沟通）
     *                  * 3参与的(我发起、我已办理、我已沟通)
     *                  * 4我已沟通的
     *                  * 5我已办的（包含我发起和我已经办，不含待审）
     * @return billId列表
     */
    public Page<FlowList> queryAll(ListParam listParam) {
        return WorkFlowTemplates.getBills(listParam);
    }

    /**
     * 查询工作流视图（html代码）
     */
    public String queryView(String id, String variable) {
        List<SysWorkflow> sysWorkflows = sysWorkflowService.queryByDataId(id);
        if (sysWorkflows == null) {
            return "";
        }

        // 只要最后一个工作流
        SysWorkflow sysWorkflowLast = sysWorkflows.get(0);
        return WorkFlowTemplates.view(sysWorkflowLast.drawBaseParam(), getAccount(), sysWorkflowLast.getBillId(), sysWorkflowLast.getProcessInstanceId(), variable);
    }

    /**
     * 查询初始工作流视图（html代码）
     * 即启动的时候工作流视图
     */
    public String queryInitView(BaseParam baseParam, String variable) {
        return WorkFlowTemplates.view(baseParam, getAccount(), variable);
    }

    /**
     * 查询初始工作流只读（没有提交按钮）视图（html代码）
     */
    public String queryInitOnlyView(BaseParam baseParam, String variable) {
        return WorkFlowTemplates.view(baseParam, "RandomOnlyViewUser", variable);
    }

    /**
     * 查询工作流只读（没有提交按钮）视图（html代码）
     */
    public String queryOnlyView(String id, String variable) {
        List<SysWorkflow> sysWorkflows = sysWorkflowService.queryByDataId(id);
        if (sysWorkflows == null) {
            return "";
        }

        // 只要最后一个工作流
        SysWorkflow sysWorkflowLast = sysWorkflows.get(0);
        return WorkFlowTemplates.view(sysWorkflowLast.drawBaseParam(), "RandomOnlyViewUser", sysWorkflowLast.getBillId(), sysWorkflowLast.getProcessInstanceId(), variable);
    }

    /**
     * 查询移动端工作流视图（html代码）
     */
    public String queryViewMoBile(String id) {
        List<SysWorkflow> sysWorkflows = sysWorkflowService.queryByDataId(id);
        if (sysWorkflows == null) {
            return "";
        }

        // 只要最后一个工作流
        SysWorkflow sysWorkflowLast = sysWorkflows.get(0);
        return WorkFlowTemplates.viewMobile(sysWorkflowLast.drawBaseParam(), getAccount(), sysWorkflowLast.getBillId(), sysWorkflowLast.getProcessInstanceId(), sysWorkflowLast.getOneTaskId());
    }

    /**
     * 查询初始工作流视图（html代码）
     * 即启动的时候工作流视图
     */
    public String queryInitViewMoBile(BaseParam baseParam) {
        return WorkFlowTemplates.viewMobile(baseParam, getAccount());
    }

    /**
     * 查询移动端工作流历史轨迹
     */
    public String queryHistoryMobile(String id) {
        List<SysWorkflow> sysWorkflows = sysWorkflowService.queryByDataId(id);
        if (sysWorkflows == null) {
            return "";
        }

        // 只要最后一个工作流
        SysWorkflow sysWorkflowLast = sysWorkflows.get(0);
        String s = WorkFlowTemplates.historyMobile(sysWorkflowLast.drawBaseParam(), sysWorkflowLast.getBillId(), sysWorkflowLast.getProcessInstanceId());
        JSONObject jsonObject = JSON.parseObject(s);
        return jsonObject.getString("data");
    }

    // 工作流模板节点信息
    public List<DefineResult> define(DefineParam defineParam) {
        String response = WorkFlowTemplates.define(defineParam);
        JSONObject resultObject = JSONObject.parseObject(response);
        if (resultObject.getInteger("code") == -1) {
            throw new IllegalArgumentException("工作流异常：" + resultObject.getString("description"));
        }
        JSONArray data = resultObject.getJSONArray("data");
        return JSONArray.parseArray(String.valueOf(data), DefineResult.class);
    }

    // 工作流模板节点信息
    public List<DefineResult> define(BaseParam baseParam, String taskCode) {
        String response = WorkFlowTemplates.define(baseParam, taskCode);
        JSONObject resultObject = JSONObject.parseObject(response);
        if (resultObject.getInteger("code") == -1) {
            throw new IllegalArgumentException("工作流异常：" + resultObject.getString("description"));
        }
        JSONArray data = resultObject.getJSONArray("data");
        return JSONArray.parseArray(String.valueOf(data), DefineResult.class);
    }

    // 获取运行中的节点处理人信息
    public List<UserResult> runTaskCandidateInfo(BaseParam baseParam, String processInstanceId) {
        String response = WorkFlowTemplates.runTaskCandidateInfo(baseParam, processInstanceId);
        JSONObject resultObject = JSONObject.parseObject(response);
        if (resultObject.getInteger("code") == -1) {
            throw new IllegalArgumentException("工作流异常：" + resultObject.getString("description"));
        }
        JSONArray data = resultObject.getJSONArray("data");
        return JSONArray.parseArray(String.valueOf(data), UserResult.class);
    }

    public List<TaskStatistics> listUserTaskStatistics(BaseParam baseParam, String startDate, String endDate, List<String> accountList) {
        String response = WorkFlowTemplates.listUserTaskStatistics(baseParam, startDate, endDate, accountList);
        JSONObject resultObject = JSONObject.parseObject(response);
        if (resultObject.getInteger("code") == -1) {
            throw new IllegalArgumentException("工作流异常：" + resultObject.getString("description"));
        }
        JSONArray data = resultObject.getJSONArray("data");
        return JSONArray.parseArray(String.valueOf(data), TaskStatistics.class);
    }


    /**
     * 根据节点id找到节点编号
     *
     * @param dataNode 节点id
     * @return 节点编号
     */
    public String getCodeById(BaseParam baseParam, String dataNode) {
        List<DefineResult> define = define(baseParam, null);
        Map<String, String> map = define.stream().collect(Collectors.toMap(DefineResult::getNodeId, DefineResult::getNodeCode));
        return map.get(dataNode);
    }

}
